package com.netease.ocr;
	 
import java.awt.Color;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import javax.imageio.ImageIO;
 
public class ImageProcessor {

	/**
	 * 颜色反转
	 * @param bufferedImage
	 */
	public static void revertColor(BufferedImage bufferedImage) {

		int h = bufferedImage.getHeight();
		int w = bufferedImage.getWidth();
		for (int x = 0; x < w; x++) {
            for (int y = 0; y < h; y++) {
                int argb = bufferedImage.getRGB(x, y);
                int r = 255 - (argb >> 16) & 0xFF;
                int g = 255 - (argb >> 8) & 0xFF;
                int b = 255 - (argb >> 0) & 0xFF;
                Color color = new Color(r,g,b);
                bufferedImage.setRGB(x, y, color.getRGB());
            }
        }
	}

	/**
	 * 中值滤波
	 * @param image
	 * @return
	 */
    public static BufferedImage getMedian(BufferedImage image) {
    	
    	int iw = image.getWidth();
    	int ih = image.getHeight();
    	int[] pixels = new int[iw * ih];
    	PixelGrabber pg = new PixelGrabber(image.getSource(), 0, 0, iw, ih, pixels, 0, iw);

        try {
            pg.grabPixels();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        ColorModel cm = ColorModel.getRGBdefault();
        for (int i = (int)ih/2; i < ih - 2; i++) {
            for (int j = 1; j < iw - 2; j++) {
                int red, green, blue;
                int alpha = cm.getAlpha(pixels[i * iw + j]);
 
                List<Integer> redList = new ArrayList<Integer> ();
                redList.add(cm.getRed(pixels[(i -1) * iw + j]));
                redList.add(cm.getRed(pixels[i * iw + j]));
                redList.add(cm.getRed(pixels[(i + 1) * iw + j]));
                
                Collections.sort(redList, new Comparator<Integer>() {
					@Override
					public int compare(Integer o1, Integer o2) {
						return o2.intValue() - o1.intValue();
					}
                	
				});
                red = redList.get(1);

                List<Integer> greenList = new ArrayList<Integer> ();
                greenList.add(cm.getGreen(pixels[(i - 1) * iw + j]));
                greenList.add(cm.getGreen(pixels[i * iw + j]));
                greenList.add(cm.getGreen(pixels[(i + 1) * iw + j]));
 
                Collections.sort(greenList, new Comparator<Integer>() {
					@Override
					public int compare(Integer o1, Integer o2) {
						return o2.intValue() - o1.intValue();
					}
                	
				});
                green = greenList.get(1);
                
                List<Integer> blueList = new ArrayList<Integer> ();
                blueList.add(cm.getBlue(pixels[(i - 1) * iw + j]));
                blueList.add(cm.getBlue(pixels[i * iw + j]));
                blueList.add(cm.getBlue(pixels[(i + 1) * iw + j]));
                
                Collections.sort(blueList, new Comparator<Integer>() {
					@Override
					public int compare(Integer o1, Integer o2) {
						return o2.intValue() - o1.intValue();
					}
                	
				});
                blue = blueList.get(1);
 
                pixels[i * iw + j] = alpha << 24 | red << 16 | green << 8 | blue;
            }
        }
        // 将数组中的象素产生一个图像
        Image tempImg = Toolkit.getDefaultToolkit().createImage(new MemoryImageSource(iw, ih, pixels, 0, iw));
        image = new BufferedImage(tempImg.getWidth(null), tempImg.getHeight(null), BufferedImage.TYPE_INT_BGR);
        image.createGraphics().drawImage(tempImg, 0, 0, null);
        return image;
    }
	
    /**
     * 加权灰度计算 Adobe RGB (1998)
     * @param bufferedImage
     * @return
     */
	public static int[][] changeGray(BufferedImage bufferedImage) {
		
		int h = bufferedImage.getHeight();
		int w = bufferedImage.getWidth();
		int[][] gray = new int[w][h];
		for (int x = 0; x < w; x++) {
            for (int y = 0; y < h; y++) {
                int argb = bufferedImage.getRGB(x, y);
                // 图像加亮（调整亮度识别率非常高）
                int r = (argb >> 16) & 0xFF;
                int g = (argb >> 8) & 0xFF;
                int b = (argb >> 0) & 0xFF;

                gray[x][y] = (int) Math.pow((Math.pow(r, 2.2) * 0.2973 + Math.pow(g, 2.2) * 0.6274 + Math.pow(b, 2.2) * 0.0753), 1/2.2);
            }
        }
		return gray;
	}
	
	/**
	 * 对验证码图片进行预处理
	 * @param file
	 * @throws IOException
	 */
	public static void processImg(File file) throws IOException {

		BufferedImage bufferedImage = ImageIO.read(file);
        int h = bufferedImage.getHeight();
        int w = bufferedImage.getWidth();

        // 颜色反转
        revertColor(bufferedImage);
        
        // 中值滤波
        bufferedImage = getMedian(bufferedImage);
        
        // 灰度化
        int[][] gray = changeGray(bufferedImage);
        
        // 二值化
        int threshold = ostu(gray, w, h);
        BufferedImage binaryBufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_BINARY);
        for (int x = 0; x < w; x++) {
            for (int y = 0; y < h; y++) {
                if (gray[x][y] > threshold) {
                    gray[x][y] |= 0x00FFFF;
                } else {
                    gray[x][y] &= 0xFF0000;
                }
                binaryBufferedImage.setRGB(x, y, gray[x][y]);
            }
        }
        revertColor(binaryBufferedImage);

        for (int y = h/2; y < h; y++) {
            for (int x = 0; x < w; x++) {
                if (isSingleLine(x, y, binaryBufferedImage)) {
                	binaryBufferedImage.setRGB(x, y, 12314112);
                }
            }
        }

//        File f = new File("E:/12306_test/" + file.getName().substring(0, file.getName().indexOf('.')) + ".tiff");
        ImageIO.write(binaryBufferedImage, "tiff", file);
	}

    public static void main(String[] args) throws IOException {
        
    	File file = new File("E:/12306_test/");
    	for(File f:file.listFiles()) {
    		processImg(f);
    	}
    }
    
    public static boolean isLightColor(int x, int y, BufferedImage image) {
    	int colorInt = image.getRGB(x, y);
    	Color color = new Color(colorInt);
    	return (color.getRed()>200 && color.getGreen()>200 && color.getBlue()>200);
    }

    public static boolean isSingleLine(int x, int y, BufferedImage image) {
    	int height = image.getHeight();
        int up = image.getRGB(x, (y-1)>0?(y-1):0);
        int down = image.getRGB(x, (y+1)<height?(y+1):(height-1));
        Color upC = new Color(up);
        Color downC = new Color(down);
        if (upC.getRed() >200 && downC.getRed() > 200) {
            return true;
        }
    	return false;
    }
 
    public static boolean isBlack(int colorInt) {
        Color color = new Color(colorInt);
        if (color.getRed() + color.getGreen() + color.getBlue() <= 300) {
            return true;
        }
        return false;
    }
    
    /** 
     *　DNA分析 　　拼字检查 　　语音辨识 　　抄袭侦测 
     *  
     */  
    public static void levenshtein(String str1,String str2) {  
        //计算两个字符串的长度。  
        int len1 = str1.length();  
        int len2 = str2.length();  
        //建立上面说的数组，比字符长度大一个空间  
        int[][] dif = new int[len1 + 1][len2 + 1];  
        //赋初值，步骤B。  
        for (int a = 0; a <= len1; a++) {  
            dif[a][0] = a;  
        }  
        for (int a = 0; a <= len2; a++) {  
            dif[0][a] = a;  
        }  
        //计算两个字符是否一样，计算左上的值  
        int temp;  
        for (int i = 1; i <= len1; i++) {  
            for (int j = 1; j <= len2; j++) {  
                if (str1.charAt(i - 1) == str2.charAt(j - 1)) {  
                    temp = 0;  
                } else {  
                    temp = 1;  
                }  
                //取三个值中最小的  
                dif[i][j] = min(dif[i - 1][j - 1] + temp, dif[i][j - 1] + 1,  
                        dif[i - 1][j] + 1);  
            }  
        }  
        System.out.println("字符串\""+str1+"\"与\""+str2+"\"的比较");  
        //取数组右下角的值，同样不同位置代表不同字符串的比较  
        System.out.println("差异步骤："+dif[len1][len2]);  
        //计算相似度  
        float similarity =1 - (float) dif[len1][len2] / Math.max(str1.length(), str2.length());  
        System.out.println("相似度："+similarity);  
    }  
  
    //得到最小值  
    private static int min(int... is) {  
        int min = Integer.MAX_VALUE;  
        for (int i : is) {  
            if (min > i) {  
                min = i;  
            }  
        }  
        return min;  
    }  
 
    public static boolean isWhite(int colorInt) {
        Color color = new Color(colorInt);
        if (color.getRed() + color.getGreen() + color.getBlue() > 300) {
            return true;
        }
        return false;
    }
 
    public static int isBlackOrWhite(int colorInt) {
        if (getColorBright(colorInt) < 30 || getColorBright(colorInt) > 730) {
            return 1;
        }
        return 0;
    }
 
    public static int getColorBright(int colorInt) {
        Color color = new Color(colorInt);
        return color.getRed() + color.getGreen() + color.getBlue();
    }
 
    /**
     * 二值化 OTSU算法
     * @param gray
     * @param w
     * @param h
     * @return
     */
    public static int ostu(int[][] gray, int w, int h) {
        int[] histData = new int[w * h];
        // Calculate histogram
        for (int x = 0; x < w; x++) {
            for (int y = 0; y < h; y++) {
                int red = 0xFF & gray[x][y];
                histData[red]++;
            }
        }
 
        // Total number of pixels
        int total = w * h;
         
        float sum = 0;
        for (int t = 0; t < 256; t++)
            sum += t * histData[t];
 
        float sumB = 0;
        int wB = 0;
        int wF = 0;
 
        float varMax = 0;
        int threshold = 0;

        for (int t = 0; t < 256; t++) {
            wB += histData[t]; // Weight Background
            if (wB == 0)
                continue;

            wF = total - wB; // Weight Foreground
            if (wF == 0)
                break;
 
            sumB += (float) (t * histData[t]);
 
            float mB = sumB / wB; // Mean Background
            float mF = (sum - sumB) / wF; // Mean Foreground
 
            float varBetween = (float) wB * (float) wF * (mB - mF) * (mB - mF);
 
            if (varBetween > varMax) {
                varMax = varBetween;
                threshold = t;
            }
        }
 
        return threshold;
    }
}